<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Git 使用教程</title>
    <style>
        body {
            font-family: 'Inter', sans-serif;
            background-color: #f8f9fa;
            color: #212529;
            line-height: 1.8;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            background-image: linear-gradient(rgba(0, 0, 0, 0.02) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 0, 0, 0.02) 1px, transparent 1px);
            background-size: 20px 20px;
        }
        .container {
            max-width: 900px;
            margin: 40px auto;
            padding: 30px;
            background-color: #ffffff;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
        }
        h1, h2, h3, h4, h5, h6 {
            font-family: 'Merriweather', serif;
            color: #343a40;
            margin-top: 1.5em;
            margin-bottom: 0.8em;
            font-weight: 700;
        }
        h1 {
            font-size: 2.8em;
            border-bottom: 2px solid #e9ecef;
            padding-bottom: 0.5em;
            margin-top: 0;
        }
        h2 {
            font-size: 2.2em;
            border-bottom: 1px solid #e9ecef;
            padding-bottom: 0.4em;
        }
        h3 {
            font-size: 1.8em;
        }
        p {
            margin-bottom: 1.2em;
            text-align: justify;
        }
        a {
            color: #3b82f6;
            text-decoration: none;
            transition: color 0.3s ease;
        }
        a:hover {
            color: #1d4ed8;
            text-decoration: underline;
        }
        ul, ol {
            padding-left: 25px;
            margin-bottom: 1.2em;
        }
        li {
            margin-bottom: 0.5em;
        }
        pre {
            background-color: #282c34; /* Darker background for code blocks */
            color: #abb2bf; /* Light text for code */
            padding: 20px;
            border-radius: 6px;
            overflow-x: auto;
            font-family: 'IBM Plex Mono', monospace;
            font-size: 0.95em;
            line-height: 1.6;
            margin-bottom: 1.5em;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        code {
            font-family: 'IBM Plex Mono', monospace;
            background-color: #e9ecef;
            padding: 0.2em 0.4em;
            border-radius: 3px;
            font-size: 0.9em;
        }
        pre code {
            background-color: transparent;
            padding: 0;
            border-radius: 0;
            font-size: inherit; /* Inherit size from pre */
            color: inherit; /* Inherit color from pre */
        }
        img {
            max-width: 100%;
            height: auto;
            border-radius: 4px;
            margin-top: 1em;
            margin-bottom: 1em;
            display: block;
            margin-left: auto;
            margin-right: auto;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        /* Table of Contents specific styling */
        .toc {
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            padding: 15px 20px;
            border-radius: 6px;
            margin-bottom: 2em;
        }
        .toc h2 {
            font-size: 1.5em;
            margin-top: 0;
            border-bottom: none;
        }
        .toc ul {
            list-style-type: none;
            padding-left: 0;
        }
        .toc ul li a {
            font-weight: 500;
        }

        /* Responsive adjustments */
        @media (max-width: 768px) {
            .container {
                margin: 20px;
                padding: 20px;
            }
            h1 {
                font-size: 2.2em;
            }
            h2 {
                font-size: 1.8em;
            }
            h3 {
                font-size: 1.5em;
            }
            pre {
                padding: 15px;
            }
        }
    </style>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&family=Merriweather:wght@400;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>Git 使用教程：从 SSH 配置到远程推送</h1>
        <p>本教程将指导完成在 Windows 环境下使用 Git 和 Gitee 进行版本控制的完整流程，包括设置 SSH 密钥、在 Gitee 上创建和克隆仓库，以及执行基本的 Git 操作。</p>

        <div class="toc">
            <h2>目录</h2>
            <ol>
                <li><a href="#1-设置-ssh-密钥">设置 SSH 密钥</a></li>
                <li><a href="#2-在-gitee-上创建仓库">在 Gitee 上创建仓库</a></li>
                <li><a href="#3-克隆仓库">克隆仓库</a></li>
                <li><a href="#4-编辑文件">编辑文件</a></li>
                <li><a href="#5-添加到暂存区">添加到暂存区</a></li>
                <li><a href="#6-提交到本地仓库">提交到本地仓库</a></li>
                <li><a href="#7-推送到远程仓库">推送到远程仓库</a></li>
                <li><a href="#8-解决-git-冲突">解决 Git 冲突</a></li>
            </ol>
        </div>

        <h2 id="1-设置-ssh-密钥">1. 设置 SSH 密钥</h2>
        <p>SSH (Secure Shell) 密钥允许您以安全的方式连接到 Gitee，无需每次都输入用户名和密码。</p>
        <h3>生成 SSH 密钥</h3>
        <ol>
            <li>打开 Git Bash (安装 Git 后会自带)。</li>
            <li>运行以下命令生成 SSH 密钥对。将 <code>your_email@example.com</code> 替换为您的 Gitee 注册邮箱：
                <pre><code class="language-bash">ssh-keygen -t rsa -C "gaocong@gmail.com"</code></pre>
            </li>
            <li>系统会提示您输入密钥文件的保存位置，直接按 Enter 键接受默认位置 (<code>~/.ssh/id_rsa</code>)。</li>
            <li>接着会提示您输入密码 (passphrase)。您可以选择设置一个密码来保护您的私钥，也可以直接按 Enter 键留空 (不推荐)。如果设置了密码，每次使用 SSH 密钥时都需要输入该密码。</li>
        </ol>
        <h3>将公钥添加到 Gitee</h3>
        <ol>
            <li>密钥生成后，您需要将公钥 (<code>id_rsa.pub</code>) 的内容添加到您的 Gitee 账户中。</li>
            <li>使用以下命令查看并复制公钥内容：
                <pre><code class="language-bash">cat ~/.ssh/id_rsa.pub</code></pre>
                复制输出的全部内容 (以 <code>ssh-rsa</code> 开头，以您的邮箱结尾)。
            </li>
            <li>登录您的 Gitee 账户。</li>
            <li>进入 “设置” -> “SSH 公钥”。</li>
            <li>点击 “添加公钥”，将复制的公钥内容粘贴到 “公钥” 文本框中，为该公钥设置一个 “标题” (例如：My Windows Laptop)，然后点击 “确定”。</li>
        </ol>
        <h3>测试 SSH 连接</h3>
        <p>在 Git Bash 中运行以下命令测试 SSH 连接是否成功：</p>
        <pre><code class="language-bash">ssh -T git@gitee.com</code></pre>
        <p>如果看到类似 <code>Hi YourUsername! You've successfully authenticated, but Gitee.com does not provide shell access.</code> 的消息，说明 SSH 配置成功。</p>
        <h3>使用 <code>~/.ssh/config</code> 文件配置特定主机和密钥</h3>
        <p>对于更高级的用户，或者当您需要管理多个 SSH 密钥（例如，一个用于 Gitee，一个用于 GitHub，或者不同的 Gitee 账户），或者希望为特定主机指定特定的密钥文件时，可以通过编辑 <code>~/.ssh/config</code> 文件来实现更精细化的控制。</p>
        <ol>
            <li><strong>打开或创建 <code>~/.ssh/config</code> 文件</strong>：
                <ul>
                    <li><strong>使用 Git Bash</strong>:
                        <pre><code class="language-bash">nano ~/.ssh/config</code></pre>
                        (或者使用 <code>vim ~/.ssh/config</code>)
                    </li>
                    <li><strong>使用 Windows 文件资源管理器</strong>:
                        导航到您的用户目录下的 <code>.ssh</code> 文件夹 (通常是 <code>C:\Users\YourUsername\.ssh\</code>，请将 <code>YourUsername</code> 替换为您的实际 Windows 用户名)。如果 <code>config</code> 文件不存在，您可以创建一个文本文件并将其重命名为 <code>config</code> (确保没有 <code>.txt</code> 扩展名)。
                    </li>
                </ul>
            </li>
            <li><strong>添加配置</strong>：<br>
                假设您为 Gitee 生成了一个名为 <code>gitee_rsa</code> (私钥) 和 <code>gitee_rsa.pub</code> (公钥) 的密钥对，并将它们存放在 <code>~/.ssh/</code> 目录 (即 <code>C:\Users\YourUsername\.ssh\</code>)。您可以添加以下内容到 <code>config</code> 文件中：
                <pre><code># Gitee Configuration
Host gitee.com
    HostName gitee.com
    User git
    IdentityFile C:\Users\YourUsername\.ssh\gitee_rsa
    IdentitiesOnly yes</code></pre>
                <ul>
                    <li><code>Host gitee.com</code>: 定义了一个配置块，适用于主机 <code>gitee.com</code>。您可以自定义这个别名，例如 <code>gitee-personal</code>。如果修改了 <code>Host</code> 别名，那么后续的 git 命令中也需要使用这个别名，例如 <code>git clone git@gitee-personal:username/repo.git</code>。</li>
                    <li><code>HostName gitee.com</code>: 实际连接的主机名。</li>
                    <li><code>User git</code>: 连接时使用的用户名，对于 Gitee 通常是 <code>git</code>。</li>
                    <li><code>IdentityFile C:\Users\YourUsername\.ssh\gitee_rsa</code>: 指定了用于此主机的私钥文件路径。请将 <code>YourUsername</code> 替换为您的 Windows 用户名，并将 <code>gitee_rsa</code> 替换为您实际的私钥文件名。在 Git Bash 中，您也可以使用 <code>~/.ssh/gitee_rsa</code> 这样的路径，<code>~</code> 代表用户主目录。</li>
                    <li><code>IdentitiesOnly yes</code>: 表示仅使用通过 <code>IdentityFile</code> 指定的密钥进行认证，忽略 ssh-agent 中可能存在的其他密钥或默认密钥。这在您有多个密钥，且不希望 SSH 尝试所有密钥时非常有用。</li>
                </ul>
            </li>
            <li><strong>保存文件并设置权限 (推荐)</strong>：<br>
                保存 <code>config</code> 文件。在类 Unix 系统 (包括 Git Bash 环境) 中，SSH 对 <code>~/.ssh</code> 目录及其内部文件的权限要求比较严格。建议将 <code>config</code> 文件权限设置为 <code>600</code> (即只有所有者可读写)：
                <pre><code class="language-bash">chmod 600 ~/.ssh/config</code></pre>
                Windows 对文件权限的处理方式与 Linux 不同，可不做此设置。
            </li>
            <li><strong>测试</strong>：<br>
                完成配置后，您可以像之前一样测试 SSH 连接：
                <pre><code class="language-bash">ssh -T git@gitee.com</code></pre>
                如果配置正确，SSH 客户端会自动根据 <code>config</code> 文件找到并使用指定的密钥进行认证。
            </li>
        </ol>

        <h2 id="2-在-gitee-上创建仓库">2. 在 Gitee 上创建仓库</h2>
        <ol>
            <li>登录您的 Gitee 账户。</li>
            <li>点击页面右上角的 “+” 号，选择 “新建仓库”。</li>
            <li>填写仓库信息：
                <ul>
                    <li><strong>仓库名称</strong>: 给您的仓库起一个名字 (例如 <code>my-first-project</code>)。</li>
                    <li><strong>仓库介绍</strong>: (可选) 对仓库进行简短描述。</li>
                    <li><strong>是否开源</strong>: 选择公开或私有。</li>
                    <li><strong>使用 Readme 文件初始化这个仓库</strong>: 建议勾选，这样会自动创建一个 <code>README.md</code> 文件。</li>
                    <li><strong>添加 .gitignore</strong>: (可选) 选择一个适合您项目类型的 <code>.gitignore</code> 模板 (例如 <code>Java</code>)。</li>
                    <li><strong>添加开源许可证</strong>: (可选) 选择一个开源许可证。</li>
                </ul>
            </li>
            <li>点击 “创建” 按钮。</li>
        </ol>
        <img src="./images/gitee创建仓库.png" alt="创建仓库">

        <h2 id="3-克隆仓库">3. 克隆仓库</h2>
        <p>创建仓库后，需要将其克隆到本地计算机。</p>
        <ol>
            <li>在 Gitee 仓库页面，找到 “克隆/下载” 按钮，选择 “SSH” 协议，并复制 SSH 地址 (例如 <code>git@gitee.com:YourUsername/my-first-project.git</code>)。</li>
            <li>打开 Git Bash 或命令提示符 (CMD) / PowerShell。</li>
            <li>进入存放项目的本地目录。</li>
            <li>运行 <code>git clone</code> 命令，粘贴您复制的 SSH 地址：
                <pre><code class="language-bash">git clone git@gitee.com:YourUsername/my-first-project.git</code></pre>
            </li>
            <li>这会在当前目录下创建一个名为 <code>my-first-project</code> 的文件夹，并将仓库内容下载到其中。</li>
            <li>进入项目目录：
                <pre><code class="language-bash">cd my-first-project</code></pre>
            </li>
        </ol>

        <h2 id="4-编辑文件">4. 编辑文件</h2>
        <p>现在您可以在本地仓库中进行更改了。</p>
        <ol>
            <li>使用您喜欢的代码编辑器 (如 VS Code, IntelliJ IDEA, Notepad++) 打开项目文件夹。</li>
            <li>创建一个新文件 (例如 <code>hello.txt</code>) 或修改现有文件 (例如 <code>README.md</code>)。<br>
                例如，在 <code>hello.txt</code> 中添加以下内容：
                <pre><code>Hello, Git!</code></pre>
            </li>
        </ol>

        <h2 id="5-添加到暂存区">5. 添加到暂存区</h2>
        <p>在提交更改之前，您需要将它们添加到 Git 的暂存区 (Staging Area)。</p>
        <ol>
            <li>打开 Git Bash 或在您的 IDE 的终端中。</li>
            <li>使用 <code>git status</code> 命令查看文件的状态，您会看到新创建或修改的文件被列为 “未跟踪的文件” (untracked files) 或 “修改尚未加入提交” (changes not staged for commit)。
                <pre><code class="language-bash">git status</code></pre>
            </li>
            <li>使用 <code>git add</code> 命令将文件添加到暂存区：
                <ul>
                    <li>添加单个文件：
                        <pre><code class="language-bash">git add hello.txt
git add README.md</code></pre>
                    </li>
                    <li>添加所有更改 (包括新文件和修改的文件)：
                        <pre><code class="language-bash">git add .</code></pre>
                    </li>
                </ul>
            </li>
            <li>再次运行 <code>git status</code>，您会看到文件状态变为 “要提交的变更” (changes to be committed)。</li>
        </ol>

        <h2 id="6-提交到本地仓库">6. 提交到本地仓库</h2>
        <p>将暂存区的更改永久保存到本地仓库的历史记录中。</p>
        <ol>
            <li>使用 <code>git commit</code> 命令提交更改，并附带一条描述性的提交信息：
                <pre><code class="language-bash">git commit -m "Add hello.txt and update README"</code></pre>
                <code>-m</code> 参数后面的字符串是本次提交的说明。
            </li>
            <li>您可以使用 <code>git log</code> 命令查看提交历史：
                <pre><code class="language-bash">git log</code></pre>
            </li>
        </ol>

        <h2 id="7-推送到远程仓库">7. 推送到远程仓库</h2>
        <p>将本地仓库的提交推送到 Gitee 上的远程仓库，以便与他人共享或备份您的工作。</p>
        <ol>
            <li>使用 <code>git push</code> 命令：
                <pre><code class="language-bash">git push origin main</code></pre>
                <ul>
                    <li><code>origin</code> 是远程仓库的默认名称。</li>
                    <li><code>main</code> 是您要推送的本地分支的名称 (Gitee 新建仓库默认分支可能是 <code>master</code> 或 <code>main</code>，请根据实际情况调整)。如果您的默认分支是 <code>master</code>，则命令为 <code>git push origin master</code>。</li>
                </ul>
                如果您在克隆仓库时，Gitee 仓库是空的 (没有勾选初始化 Readme)，并且这是第一次推送，您可能需要使用：
                <pre><code class="language-bash">git push -u origin main</code></pre>
                <code>-u</code> 参数会将本地的 <code>main</code> 分支与远程的 <code>origin/main</code> 分支关联起来，之后推送时只需 <code>git push</code>。
            </li>
            <li>如果之前设置了 SSH 密钥的密码，系统可能会提示您输入密码。</li>
            <li>推送成功后，您可以在 Gitee 仓库页面上看到您的更改。</li>
        </ol>
        <p>以上步骤如果正常，则完成了从配置 SSH 到将更改推送到远程仓库的整个 Git 工作流程。</p>

        <h2 id="8-解决-git-冲突">8. 解决 Git 冲突</h2>
        <p>当多个开发者同时修改了同一个文件的同一部分，或者在合并 (merge) 操作时，如果 Git 无法自动合并这些更改，就会发生冲突 (Conflict)。这时需要手动解决冲突。</p>
        <h3>冲突是如何发生的？</h3>
        <ul>
            <li><strong>合并分支 (Merge)</strong>: 当你尝试将一个分支的更改合并到另一个分支，而两个分支都修改了同一个文件的相同行时。</li>
            <li><strong>变基操作 (Rebase)</strong>: 当你将一个分支的提交应用到另一个分支的顶端，如果途中的某些提交与目标分支的提交修改了相同内容。</li>
            <li><strong>拉取远程更改 (Pull)</strong>: <code>git pull</code> 本质上是 <code>git fetch</code> 后跟 <code>git merge</code>。如果远程更改与你的本地未推送更改冲突，也会发生。</li>
        </ul>
        <h3>如何识别冲突？</h3>
        <ol>
            <li><strong>Git 提示</strong>: 在执行 <code>git merge</code> 或 <code>git pull</code> 等操作时，如果发生冲突，Git 会在终端输出提示信息，告知哪些文件存在冲突。
                <pre><code class="language-bash">Auto-merging your-file.txt
CONFLICT (content): Merge conflict in your-file.txt
Automatic merge failed; fix conflicts and then commit the result.</code></pre>
            </li>
            <li><strong><code>git status</code></strong>: 运行 <code>git status</code> 命令会显示处于 “未合并路径” (Unmerged paths) 状态的文件，这些就是冲突文件。
                <pre><code class="language-bash">$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add &lt;file&gt;..." to mark resolution)
        both modified:   your-file.txt

no changes added to commit (use "git add" and/or "git commit -a")</code></pre>
            </li>
        </ol>
        <h3>如何解决冲突？</h3>
        <ol>
            <li><strong>打开冲突文件</strong>: 使用文本编辑器打开标记为冲突的文件。Git 会在文件中用特殊的标记来标示冲突的部分：
                <pre><code>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
这是你当前分支 (HEAD) 的内容。
=======
这是你正在合并的分支 (e.g., feature-branch) 的内容。
&gt;&gt;&gt;&gt;&gt;&gt;&gt; feature-branch</code></pre>
                <ul>
                    <li><code>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD</code>: 标记冲突区域的开始，直到 <code>=======</code> 都是你当前所在分支 (通常是 <code>HEAD</code> 指向的分支) 的内容。</li>
                    <li><code>=======</code>: 分隔符，分隔了两个冲突版本的内容。</li>
                    <li><code>&gt;&gt;&gt;&gt;&gt;&gt;&gt; other-branch-name</code>: 标记冲突区域的结束，从 <code>=======</code> 到这里是你正在合并进来的分支的内容。</li>
                </ul>
            </li>
            <li><strong>手动编辑文件</strong>:
                <ul>
                    <li>仔细阅读冲突标记之间的代码。</li>
                    <li>决定保留哪些更改，或者如何组合这些更改。你可能需要保留 <code>HEAD</code> 的版本，或者另一个分支的版本，或者两者的结合，甚至编写全新的代码。</li>
                    <li><strong>删除所有冲突标记</strong> (<code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code>, <code>=======</code>, <code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code>)。确保最终文件只包含你希望保留的正确代码。</li>
                </ul>
                例如，解决后 <code>your-file.txt</code> 可能看起来像这样 (假设你决定保留两者的内容并稍作修改)：
                <pre><code>这是你当前分支 (HEAD) 的内容，经过了修改。
这也是你正在合并的分支 (e.g., feature-branch) 的内容，也经过了修改。</code></pre>
            </li>
            <li><strong>添加到暂存区</strong>: 在解决了文件中的所有冲突并保存后，使用 <code>git add</code> 命令将该文件标记为已解决。
                <pre><code class="language-bash">git add your-file.txt</code></pre>
                如果你有多个冲突文件，需要对每个文件都执行此操作。
            </li>
            <li><strong>完成合并</strong>:
                <ul>
                    <li><strong>如果是合并 (merge) 操作</strong>: 当所有冲突文件都已解决并 <code>git add</code> 之后，执行 <code>git commit</code> 来完成合并。Git 通常会自动生成一个合并提交信息，你可以直接使用或修改它。
                        <pre><code class="language-bash">git commit</code></pre>
                        (此时不需要 <code>-m</code> 参数，Git 会打开编辑器让你确认或修改提交信息)
                    </li>
                </ul>
            </li>
        </ol>
    </div>
</body>
</html>